package com.fine.hair.applet.service.impl;

import cn.hutool.core.lang.Snowflake;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Constants;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fine.hair.applet.mapper.UserLoginAccountMapper;
import com.fine.hair.applet.mapper.UserMapper;
import com.fine.hair.applet.service.UserService;
import com.fine.hair.comm.redis.RedisService;
import com.fine.hair.comm.wx.WxClient;
import com.fine.hair.comm.dto.wx.WxLoginDto;
import com.fine.hair.comm.enums.AppType;
import com.fine.hair.comm.model.User;
import com.fine.hair.comm.model.UserLoginAccount;
import com.fine.hair.comm.pojo.wx.WxCode2SessionResponse;
import com.fine.hair.comm.utils.ApiResponse;
import com.fine.hair.comm.vo.LoginResultVo;
import com.fine.hair.comm.vo.WxLiteUserInfo;
import com.fine.hair.comm.vo.WxLoginResultVo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.UUID;

/**
 * <p>${Description}</p>
 *
 * @author mouseyCat
 * @date 2020/9/7 20:44
 */
@Slf4j
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {

    @Autowired
    private WxClient wxClient;

    @Resource
    private UserLoginAccountMapper userLoginAccountMapper;

    @Resource
    private UserMapper userMapper;

    @Autowired
    private Snowflake snowflake;

    @Autowired
    private RedisService redisService;

    @Override
    public ApiResponse<String> getOpenId(String code) {
        // 在 userLoginAccount 创建新的数据
        WxCode2SessionResponse wxCodeRes = wxClient.code2Session(code);

        // 查询是否存在
        LambdaQueryWrapper<UserLoginAccount> uQw = new LambdaQueryWrapper<>();
        uQw.eq(UserLoginAccount::getWxAccount, wxCodeRes.getOpenId());
        UserLoginAccount userLoginAccount1 = userLoginAccountMapper.selectOne(uQw);
        if (userLoginAccount1 == null) {

            // 保存 sessionKey openId
            UserLoginAccount userLoginAccount = new UserLoginAccount();
            userLoginAccount.setWxAccountType(AppType.WX_LITE.getCode());
            userLoginAccount.setUserId(snowflake.nextIdStr());
            userLoginAccount.setWxAccount(wxCodeRes.getOpenId());
            userLoginAccount.setSessionKey(wxCodeRes.getSessionKey());
            userLoginAccountMapper.insert(userLoginAccount);
            return ApiResponse.ofSuccess(wxCodeRes.getOpenId());
        }
        userLoginAccount1.setSessionKey(wxCodeRes.getSessionKey());
        LambdaQueryWrapper<UserLoginAccount> uQw2 = new LambdaQueryWrapper<>();
        uQw2.eq(UserLoginAccount::getWxAccount, wxCodeRes.getOpenId());
        userLoginAccountMapper.update(userLoginAccount1, uQw2);

        return ApiResponse.ofSuccess(wxCodeRes.getOpenId());
    }

    @Override
    public WxLoginResultVo wxLogin(WxLiteUserInfo wxLiteUserInfo, WxLoginDto param) {

        WxLoginResultVo result = new WxLoginResultVo();
        log.info(">>>>>>>>>>>>>>>>>>> {}", wxLiteUserInfo);
        UserLoginAccount userLoginAccount = userLoginAccountMapper.getUserLoginAccount(
                AppType.WX_LITE.getCode(),
                param.getOpenId());
        log.info(">>>>>>>>>>>>>>>>>>>>>>>>> {}", userLoginAccount);
        //userLoginAccount.setAddress(wxLiteUserInfo.getProvince() + Constants.DASH + wxLiteUserInfo.getCity());
        //userLoginAccount.setSex(SexType.MALE.getCode().equals(Integer.valueOf(wxLiteUserInfo.getGender())) ? SexType.MALE.getMessage() : SexType.FEMALE.getMessage());
        //userLoginAccountMapper.updateByuUserId(userLoginAccount);

        // 未注册则为 null
        User user = userMapper.selectById(userLoginAccount.getUserId());


        if (user != null) {
            result.setOpenId(wxLiteUserInfo.getOpenId())
                    .setUnionId(wxLiteUserInfo.getUnionId())
                    .setNickName(user.getNickName())
                    .setHeadIcon(wxLiteUserInfo.getAvatarUrl());
        } else {
            result.setOpenId(wxLiteUserInfo.getOpenId())
                    .setUnionId(wxLiteUserInfo.getUnionId())
                    .setNickName(wxLiteUserInfo.getNickName())
                    .setHeadIcon(wxLiteUserInfo.getAvatarUrl());
        }

        if (user == null) {
            return result;
        }
        log.info("1>>>>>>>>>>>>>>>>>>>>user {}", user);
        user.setPhoneNumber(wxLiteUserInfo.getPhoneNumber());
        log.info("2>>>>>>>>>>>>>>>>>>>>user {}", user);
        userMapper.updateById(user);


        //更新用户信息

        user.setAddress(wxLiteUserInfo.getProvince() + Constants.DASH + wxLiteUserInfo.getCity());
        //user.setSex(SexType.MALE.getCode().equals(Integer.valueOf(wxLiteUserInfo.getGender())) ? SexType.MALE.getMessage() : SexType.FEMALE.getMessage());
        // 查询用户得 openid
        LambdaQueryWrapper<UserLoginAccount> ulaQw = new LambdaQueryWrapper<>();
        ulaQw.eq(UserLoginAccount::getUserId, user.getId());
        UserLoginAccount userLoginAccount1 = userLoginAccountMapper.selectOne(ulaQw);
        String openId = userLoginAccount1.getWxAccount();
        LoginResultVo userToken = this.updateLoginToken(AppType.WX_LITE, user.getId(), user, openId);
        log.info("loginA 的 userToken 为 {}", userToken);
        result.setToken(userToken.getToken());
        BeanUtils.copyProperties(userToken, result, "openId", "unionId");
        result.setId(user.getId());

        return result;
    }

    @Override
    public WxLoginResultVo wxLiteRegister(String phone, String wxLiteOpenId, String unionId,
                                          String nickname, String headIcon, Integer gender) {
        log.info("进入到微信注册方法，phone = {}, wxLiteOpenId = {}, unionId = {}, nickname = {}, headIcon = {}", phone, wxLiteOpenId, unionId, nickname, headIcon);

        WxLoginResultVo result = new WxLoginResultVo();
        result.setOpenId(wxLiteOpenId).setUnionId(unionId).setHeadIcon(headIcon).setNickName(nickname);
        LambdaQueryWrapper<User> userQw = new LambdaQueryWrapper<>();
        userQw.eq(User::getOpenId, wxLiteOpenId);
        User user = userMapper.selectOne(userQw);


        if (user != null) {
            if (StrUtil.isNotBlank(user.getHeadPhoto())) {
                // 查询用户得 openid
                UserLoginAccount userLoginAccount = userLoginAccountMapper.selectOne(new LambdaQueryWrapper<UserLoginAccount>().eq(UserLoginAccount::getUserId, user.getId()));
                String openId = userLoginAccount.getWxAccount();

                log.info("同一个人用相同的手机号和微信登录");
                LoginResultVo userToken = this.updateLoginToken(AppType.WX_LITE, user.getId(), user, openId);
                log.info("loginB 的 userToken 为 {}", userToken);
                BeanUtils.copyProperties(userToken, result, "openId", "unionId");
                return result;
            }
        } else {
            user = register(phone, nickname, headIcon, wxLiteOpenId, gender);
        }

        // 查询用户得 openid
        UserLoginAccount userLoginAccount = userLoginAccountMapper.selectOne(new LambdaQueryWrapper<UserLoginAccount>().eq(UserLoginAccount::getUserId, user.getId()));
        String openId = userLoginAccount.getWxAccount();
        // 更新 redis 缓存
        LoginResultVo userToken = this.updateLoginToken(AppType.WX_LITE, user.getId(), user, openId);

        result.setToken(userToken.getToken());
        BeanUtils.copyProperties(userToken, result, "openId", "unionId");
        result.setId(user.getId().toString());
        return result;
    }


    @Transactional(rollbackFor = Exception.class)
    public User migration(String phone, String nickName, String headIcon, String openId) {
        log.info(">>>>>>>>>>>>>>>>>>我是迁移");
        log.info(">> phone = {}, name = {}", phone, nickName);
        // 根据openId 查询 uid
        UserLoginAccount userLoginAccount = userLoginAccountMapper.selectOne(new LambdaQueryWrapper<UserLoginAccount>().eq(UserLoginAccount::getWxAccount, openId));

        // 根据手机号查询用户
        User user = userMapper.selectUserByPhoneNumber(phone);

        userLoginAccountMapper.updateUIdByUsername(userLoginAccount.getWxAccount(), user.getId());

        User newUser = User.builder().id(user.getId())
                //.nickName(nickName).sex(userLoginAccount.getSex())
                .headPhoto(headIcon).address(userLoginAccount.getAddress()).build();
        // 添加用户
        userMapper.updateById(newUser);
        User user2 = userMapper.selectOne(new LambdaQueryWrapper<User>().eq(User::getPhoneNumber, phone));

        log.info("<<");
        return user2;
    }

    @Transactional(rollbackFor = Exception.class)
    public User register(String phone, String nickName, String headIcon, String openId, Integer gender) {
        log.info("执行微信注册操作，phone = {}, nickName = {}, headIcon = {}， openId = {}", phone, nickName, headIcon, openId);
        // 根据openId 查询 uid
        LambdaQueryWrapper<UserLoginAccount> uQw = new LambdaQueryWrapper<>();
        uQw.eq(UserLoginAccount::getWxAccount, openId);
        UserLoginAccount userLoginAccount = userLoginAccountMapper.selectOne(uQw);
        User newUser = User.builder().id(userLoginAccount.getUserId()).headPhoto(headIcon)
                .phoneNumber(phone).nickName(nickName)
                .sex(userLoginAccount.getSex()).address(userLoginAccount.getAddress())
                .openId(openId)
                .sex(gender==1 ? "男" : "女")
                .build();
        User user = userMapper.selectOne(new LambdaQueryWrapper<User>().eq(User::getPhoneNumber, phone));
        if (user == null) {
            // 添加用户
            userMapper.insertOrUpdate(newUser);
        } else {
            // 用户已从后台导入
            user.setId(userLoginAccount.getUserId());
            user.setHeadPhoto(headIcon);
            user.setAddress(userLoginAccount.getAddress());
            user.setOpenId(openId);
            userMapper.update(user, new LambdaQueryWrapper<User>().eq(User::getPhoneNumber, phone));
        }
        return userMapper.selectOne(new LambdaQueryWrapper<User>().eq(User::getOpenId, openId));
    }

    @Transactional(rollbackFor = Exception.class)
    LoginResultVo updateLoginToken(AppType appType, String uid, User user, String openId) {
        log.info("执行更新用户登陆 token 操作");
        LoginResultVo userToken = redisService.getUserToken(appType, uid, openId);
        if (userToken != null) {
            BeanUtils.copyProperties(user, userToken);
            redisService.updateUserToken(appType, userToken, openId);
            return userToken;
        }

        String token = UUID.randomUUID().toString().replace(Constants.DASH, "");
        LoginResultVo result = new LoginResultVo();
        if (user == null) {
            user = userMapper.selectById(uid);
        }
        BeanUtils.copyProperties(user, result);
        result.setToken(token);
        LambdaQueryWrapper<User> userQw = new LambdaQueryWrapper<>();
        userQw.eq(User::getId, user.getId());
        userQw.eq(User::getStatus, 0L);
        redisService.updateUserToken(appType, result, openId);
        return result;
    }
}




